
#include "ov2643.h"
#include "sensor.h"

// ov2643 i2c slaver address micro-definition
#define OV2643_I2C_DEV (0x60)
#define OV2643_MSLEEP(ms) do{usleep((ms) << 10);}while(0)

#define NOT_REG		(0xFF)
#define DEFAULT_DEALY_TIME	(100)		//5ms

static OV2643_WRITE_FUNC _ov2643_w = NULL;
static OV2643_READ_FUNC _ov2643_r = NULL;

static int ov2643_write(uint16_t addr, uint8_t val)
{
	if(_ov2643_w){
		return _ov2643_w(OV2643_I2C_DEV, addr, val);
	}
	return -1;
}

static uint8_t ov2643_read(uint16_t addr)
{
	if(_ov2643_r){
		return _ov2643_r(OV2643_I2C_DEV, addr);
	}
	return 0;
}

int OV2643_install(OV2643_READ_FUNC rfunc, OV2643_WRITE_FUNC wfunc)
{
	if(!wfunc || !rfunc){
		return -1;
	}
	// install r/w function
	_ov2643_r = rfunc;
	_ov2643_w = wfunc;
	return 0;
}

int OV2643_check()
{
	uint8_t ucode_msb = 0;
	uint8_t ucode_lsb = 0;
	ucode_msb = ov2643_read(0x0A);
	ucode_lsb = ov2643_read(0x0B);	
	if((ucode_msb != 0x26) || (ucode_lsb != 0x43))
	{
		printf("read Prodect ID Number MSB is %x\n", ucode_msb);
		printf("read Prodect ID Number LSB is %x\n", ucode_lsb);
		printf("check OV2643 ID error.\n");
		return -1;
	}else{
		printf("Find sensor ID = 0x%x%x.\r\n", ucode_msb, ucode_lsb);
	}
	
	return 0;
}
#if 1   //for debug
void display_index(void)
{
    int i;

    printf("    ");
    for(i=0; i < 16; i++) {
        printf("%02x ",i);
    }
    printf("\n");
}


void dump_reg(void)
{
#if 1
    unsigned char reg;
    int i,j ;
    
    j = 0;
    printf("*****************display regs **************** \n");
    display_index();
    for(i=0; i < 256; i++) {
        if(i == 0)printf("\n%02x  ",j++);
        reg = ov2643_read( i);
        printf("%02x ",reg);
        if((i+1)%16 == 0)printf("\n%02x  ",j++ << 4);
    }
    printf("\n");
#else
    unsigned char reg;
    int i,j ;
    
    j = 0;
    printf("*****************display regs **************** \n");
    display_index();
    for(i=0; i < 256; i++) {
        printf("{0x%02x,",i);
        reg = ov2643_read( i);
        printf("0x%02x},\n ",reg);
    }
    printf("\n");  
#endif
}
#endif  //end for debug

#define CHIP_DELAY    0xFF


unsigned char init720P[][2] =
{
{0x12,0xe8},	//soft reset
{NOT_REG, DEFAULT_DEALY_TIME},//delay ... ms
{0x12,0x68},	//0x48},		//flip/mirror
{0xc3,0xff},//href ,vref output/input
{0xc4,0xff},//data output
//{0x3d,0x48},//enter sleep mode
//{0xdd,0xa5}, //anlog control register
{0x0e,0xb4},//0x10},0xb4=pclk:72M,fps:30;0xb8=pclk:48M,fps:20
{0x10,0x0a},
{0x11,0x00},//0x01
{0x0f,0x14},

{0x29,0x06},//HTS MSB
{0x2a,0x40},//HTS LSB
{0x2b,0x02},//0x03},//VTS MSB
{0x2c,0xee},//0x84},//VTS LSB
{0x2d,0x00},//EXVTS MSB
{0x2e,0x00},//EXVTS LSB

//{0x3d,0x08},	//exit sleep mode
//{NOT_REG,DEFAULT_DEALY_TIME},

};



unsigned char OV2643Reg[][2] =
{
{0x12,0x80},	//soft reset
{NOT_REG, DEFAULT_DEALY_TIME},//delay ... ms
{0xc3,0x1f},
{0xc4,0xff},
{0x3d,0x48},//enter sleep mode
{0xdd,0xa5},
{0x0e,0xb4},//0x10},0xb4=pclk:72M,fps:30;0xb8=pclk:48M,fps:20
{0x10,0x0a},
{0x11,0x00},//0x01
{0x0f,0x14},
{NOT_REG, DEFAULT_DEALY_TIME},//delay ...ms
{0x00,0x01},
{0x01,0x03},
{0x02,0x00},
{0x03,0x3d},
{0x04,0x00},
{0x05,0x44},	//AWB gain red[11:4]
{0x06,0x40},//AWB gain green[11:4]
{0x07,0x53},//AWB gain blue[11:4]
{0x08,0xf0},//bit[7:4]: AWB gain red[3:0]; bit[3:0]:AWB gain green[3:0]
{0x09,0x0c},//bit[3:0]: AWB gain blue[3:0]
// {0x0a,0x26},//pidh
// {0x0b,0x43},//pidl
{0x0c,0x00},
{0x0d,0x20},
//{0x0e,0xb4},//0x10},
//{0x0f,0x14},
//{0x10,0x0a},
//{0x11,0x00},

{0x12,0x48},
{0x29,0x06},//HTS MSB
{0x2a,0x40},//HTS LSB
{0x2b,0x02},//0x03},//VTS MSB
{0x2c,0xee},//0x84},//VTS LSB
{0x2d,0x00},//EXVTS MSB
{0x2e,0x00},//EXVTS LSB
	
{0x13,0xff},//auto AEC,AGC...
{0x14,0xa0},
{0x15,0x42},
{0x16,0x90},
{0x17,0x40},
{0x18,0x2c},
{0x19,0x24},
{0x1a,0x71},
{0x1b,0x2b},
{0x1c,0x22},
{0x1d,0x02},//0x18},	//band
{0x1e,0x00},	
{0x1f,0xc3},//0x3d},	//band
{0x20,0x01},
{0x21,0x25},
{0x22,0x00},
{0x23,0x0c},
{0x24,0x50},
{0x25,0x08},
{0x26,0x2d},
{0x27,0x04},
{0x28,0x42},
//////////////////////////
{0x2f,0xec},
{0x30,0xa9},
{0x31,0xa9},
{0x32,0xa9},
{0x33,0xa9},
{0x34,0x55},
{0x35,0x10},//0x04},//blc
{0x36,0x10},//0x04},//blc
{0x37,0xe8},
{0x38,0x34},
{0x39,0xd0},//0x10},
{0x3a,0x00},
{0x3b,0x00},
{0x3c,0xa4},
//{0x3d,0x48},//0x08},
{0x3e,0x04},
{0x3f,0x02},
{0x40,0xfb},
{0x41,0x1f},
{0x42,0x00},
{0x43,0x00},//isp test mode:bar+real  80
{0x44,0x01},
{0x45,0x03},
{0x46,0x04},
{0x47,0x3f},
{0x48,0x0c},
{0x49,0x0f},
{0x4a,0xbb},
{0x4b,0xbb},
{0x4c,0x02},
{0x4d,0x90},
{0x4e,0x01},
{0x4f,0x78},
{0x50,0x43},//0x54},
{0x51,0x28},
{0x52,0x67},
{0x53,0x02},
{0x54,0x92},
{0x55,0x01},
{0x56,0x70},
{0x57,0x44},
{0x58,0x20},
{0x59,0x66},
{0x5a,0x02},
{0x5b,0x90},
{0x5c,0x01},
{0x5d,0x88},
{0x5e,0x44},
{0x5f,0x00},
{0x60,0x66},
{0x61,0x0c},
{0x62,0x06},
{0x63,0x80},
{0x64,0x80},
{0x65,0x04},
{0x66,0x07},
{0x67,0x19},
{0x68,0x34},
{0x69,0x4a},
{0x6a,0x5a},
{0x6b,0x67},
{0x6c,0x71},
{0x6d,0x7c},
{0x6e,0x8c},
{0x6f,0x9b},
{0x70,0xa9},
{0x71,0xc0},
{0x72,0xd5},
{0x73,0xe8},
{0x74,0x20},
{0x75,0x6a},
{0x76,0x11},
{0x77,0x92},
{0x78,0xa1},
{0x79,0xe1},
{0x7a,0x02},
{0x7b,0xff},
{0x7c,0x0e},
{0x7d,0x12},
{0x7e,0x12},
{0x7f,0x54},
{0x80,0x78},
{0x81,0xa2},
{0x82,0x80},
{0x83,0x4e},
{0x84,0x40},
{0x85,0x4c},
{0x86,0x43},
{0x87,0xf8},
{0x88,0x08},
{0x89,0x70},
{0x8a,0xf0},
{0x8b,0xf0},
{0x8c,0x40},
{0x8d,0x40},
{0x8e,0x40},
{0x8f,0x1c},
{0x90,0xef},
{0x91,0x08},
{0x92,0x20},
{0x93,0x10},
{0x94,0x08},
{0x95,0x01},
{0x96,0x10},
{0x97,0x08},
{0x98,0x04},
{0x99,0x02},
{0x9a,0x02},
{0x9b,0x69},
{0x9c,0x7d},
{0x9d,0x7d},
{0x9e,0x69},
{0x9f,0x0a},
{0xa0,0x0f},
{0xa1,0x18},
{0xa2,0x10},
{0xa3,0x0a},
{0xa4,0x0f},
{0xa5,0x10},
{0xa6,0x16},
{0xa7,0x0a},
{0xa8,0x0f},
{0xa9,0x00},
{0xaa,0xa6},
{0xab,0x28},
{0xac,0x48},
{0xad,0x10},
{0xae,0x18},
{0xaf,0x75},
{0xb0,0x8c},
{0xb1,0x8d},
{0xb2,0x8c},
{0xb3,0x00},
{0xb4,0x98},
{0xb5,0x00},
{0xb6,0x07},	
{0xb7,0x90},//0x90},	//hue cos
{0xb8,0x00},//0x08},	//hue sin
{0xb9,0x3c},
{0xba,0x28},
{0xbb,0x00},
{0xbc,0x20},
{0xbd,0x00},
{0xbe,0x01},
{0xbf,0x0c},
{0xc0,0x3e},
{0xc1,0x00},
{0xc2,0x00},
//{0xc3,0xff},
//{0xc4,0xff},
{0xc5,0x90},
{0xc6,0x30},
{0xc7,0x0a},
{0xc8,0x00},
{0xc9,0x08},
{0xca,0x00},
{0xcb,0x00},
{0xcc,0x00},
{0xcd,0x12},
{0xce,0x00},
{0xcf,0x00},
{0xd0,0x93},
{0xd1,0xc1},
{0xd2,0xf0},
{0xd3,0x02},
{0xd4,0x00},
{0xd5,0x00},
{0xd6,0x00},
{0xd7,0x40},
{0xd8,0x00},
{0xd9,0x41},
{0xda,0x07},
{0xdb,0x00},
{0xdc,0x2b},
//{0xdd,0xa5},
{0xde,0x4c},
{0xdf,0x10},
{0xe0,0x00},
{0xe1,0x00},
{0xe2,0x00},
{0xe3,0x00},
{0xe4,0x00},
{0xe5,0x00},
{0xe6,0x00},
{0xe7,0x00},
{0xe8,0x00},
{0xe9,0x00},
{0xea,0x00},
{0xeb,0x00},
{0xec,0x00},
{0xed,0x00},
{0xee,0x00},
{0xef,0x00},
{0xf0,0x00},
{0xf1,0x00},
{0xf2,0x00},
{0xf3,0x00},
{0xf4,0x00},
{0xf5,0x00},
{0xf6,0x00},
{0xf7,0x00},
{0xf8,0x00},
{0xf9,0x00},
{0xfa,0x00},
{0xfb,0x00},
{0xfc,0x00},
{0xfd,0x00},
{0xfe,0x00},
{0xff,0x00},

{0x3d,0x08},	//exit sleep mode
{NOT_REG,DEFAULT_DEALY_TIME},
};

////////////////////////////////////
int OV2643_init(int freq)
{
	int i;
	for(i=0; i<(sizeof(OV2643Reg)/2); i++)
	{
		if (OV2643Reg[i][0] == NOT_REG) 
			usleep(1000*OV2643Reg[i][1]);
		else
			ov2643_write(OV2643Reg[i][0], OV2643Reg[i][1]);
			
	}
	return 0;
}

void OV2643_mirror_flip(unsigned char mode)
{
	unsigned char reg0x12=0;
	reg0x12=ov2643_read(0x12);
	switch(mode)
	{
		case MODE_MIRROR:
			ov2643_write(0x12,0x20 | (reg0x12 & 0xcf));
			break;
		case MODE_FLIP:
			ov2643_write(0x12,0x10 | (reg0x12 & 0xcf));
			break;
		case MODE_MIRROR_FLIP:
			ov2643_write(0x12,0x30 | (reg0x12 & 0xcf));
			break;
		case MODE_NORMAL:
			ov2643_write(0x12,0x00 | (reg0x12 & 0xcf));
			break;
		default:
			ov2643_write(0x12,0x00 | (reg0x12 & 0xcf));
			break;
	}
}
void OV2643_test_mode(unsigned char enable)
{
	if(enable==1)
		ov2643_write(0x43,0x80);
	else
		ov2643_write(0x43,0x00);
}
void OV2643_AWB(unsigned char mode)
{
if(mode==AWB_ADVANCED)
	ov2643_write(0x75,0x6e);
else
	ov2643_write(0x75,0x6a);
}
void OV2643_light_mode(unsigned char mode)
{
	switch(mode)
	{
		case LIGHT_MODE_SUNNY:
			ov2643_write(0x13,0xfb);
			ov2643_write(0x05,0x5e);
			ov2643_write(0x06,0x41);
			ov2643_write(0x07,0x54);
			ov2643_write(0x08,0x00);
			ov2643_write(0x09,0x00);
			break;
		case LIGHT_MODE_CLOUDY:
			ov2643_write(0x13,0xfb);
			ov2643_write(0x05,0x65);
			ov2643_write(0x06,0x41);
			ov2643_write(0x07,0x4f);
			ov2643_write(0x08,0x00);
			ov2643_write(0x09,0x00);
			break;
		case LIGHT_MODE_OFFICE:
			ov2643_write(0x13,0xfb);
			ov2643_write(0x05,0x52);
			ov2643_write(0x06,0x41);
			ov2643_write(0x07,0x66);
			ov2643_write(0x08,0x00);
			ov2643_write(0x09,0x00);
			break;
		case LIGHT_MODE_HOME:
			ov2643_write(0x13,0xfb);
			ov2643_write(0x05,0x42);
			ov2643_write(0x06,0x3f);
			ov2643_write(0x07,0x71);
			ov2643_write(0x08,0x00);
			ov2643_write(0x09,0x00);
			break;
		case LIGHT_MODE_AUTO:
			ov2643_write(0x13,0xff);
			break;
		default:
			ov2643_write(0x13,0xff);
			break;
	}
}
void OV2643_set_hue(unsigned short val)
{
	
	unsigned char reg0xb6=ov2643_read(0xb6);
	ov2643_write(0xb6,reg0xb6 | 0x01);
	if(val==0)
	{
		ov2643_write(0xb7,0x80); //hue cos
		ov2643_write(0xb8,0x00); //hue sin
	}
	else
	{
		ov2643_write(0xb7,val & 0xff);	
		ov2643_write(0xb8,(val >> 8) & 0xff);	
	}
}

void OV2643_set_saturation(unsigned char val)
{
	unsigned char reg0xb5=ov2643_read(0xb5);	
	if(val==0)
	{
		ov2643_write(0xb5,reg0xb5 | 0x20);	//0x21
		ov2643_write(0xb9,0x40); //u-adjust
		ov2643_write(0xba,0x28); //v-adjust
	}
	else{
		ov2643_write(0xb5,reg0xb5 & 0xdf);	//0x21
		ov2643_write(0xb9,val);	//u-adjust
		ov2643_write(0xba,val);	//v-adjust
	}
	//ov2643_write(0xc0,0x00);	//lsb if 0xb5[5] is 1
}
void OV2643_set_brightness(unsigned char val)
{
	unsigned char reg0xbe=ov2643_read(0xbe);
	if(val<128)
	{
		ov2643_write(0xbe,reg0xbe | 0x08);
		ov2643_write(0xbd,(128-val)*2);
	}
	else if (val<256){
		ov2643_write(0xbe,reg0xbe & 0xF7);
		ov2643_write(0xbd,(val-128)*2);
	}
	else{
		ov2643_write(0xbe,reg0xbe & 0xF7);
		ov2643_write(0xbd,0x00);
	}
}

void OV2643_set_contrast(unsigned char val)
{
	ov2643_write(0xbb,val);
	ov2643_write(0xbc,val);
}

void OV2643_set_exposure(unsigned char val)
{
	#define MAX_EXPOSURE	7
	if(val==0 || val >7)
	{
		val==4;
	}
	if(val==1)
	{
		ov2643_write(0x18, 0x10);
		ov2643_write(0x19, 0x08);
		ov2643_write(0x1a, 0x20);
	}
	else if(val == 2)
	{
		ov2643_write(0x18, 0x18);
		ov2643_write(0x19, 0x10);
		ov2643_write(0x1a, 0x30);
	}
	else if(val == 3)
	{
		ov2643_write(0x18, 0x20);
		ov2643_write(0x19, 0x18);
		ov2643_write(0x1a, 0x40);
	}
	else if(val == 4)
	{
		ov2643_write(0x18, 0x24);
		ov2643_write(0x19, 0x1c);
		ov2643_write(0x1a, 0x40);
	}
	else if(val==5)
	{
		ov2643_write(0x18, 0x28);
		ov2643_write(0x19, 0x20);
		ov2643_write(0x1a, 0x41);
	}
	else if(val==6)
	{
		ov2643_write(0x18, 0x30);
		ov2643_write(0x19, 0x28);
		ov2643_write(0x1a, 0x61);
	}
	else if(val==7)
	{
		ov2643_write(0x18, 0x38);
		ov2643_write(0x19, 0x30);
		ov2643_write(0x1a, 0x71);
	}
		
}
void OV2643_set_sharpness(unsigned char val)
{
	if(val>5)
		val=0;
	if(val==0)	//auto
	{
		ov2643_write(0x9f, 0x0a);
		ov2643_write(0xa0, 0x0f);
		ov2643_write(0xa7, 0x0a);
		ov2643_write(0xa8, 0x0f);
	}
	else if(val==5)
	{
		ov2643_write(0xa1, 0x1f);
		ov2643_write(0xa2, 0x0c);
	}
	else if(val==4)
	{
		ov2643_write(0xa1, 0x1c);
		ov2643_write(0xa2, 0x08);
	}
	else if(val==3)
	{
		ov2643_write(0xa1, 0x18);
		ov2643_write(0xa2, 0x04);
	}
	else if(val==2)
	{
		ov2643_write(0xa1, 0x14);
		ov2643_write(0xa2, 0x02);
	}
	else if(val==1)
	{
		ov2643_write(0xa1, 0x10);
		ov2643_write(0xa2, 0x00);
	}

}

void OV2643_color_mode(unsigned char mode)
{
	switch(mode)
	{
		case COLOR_MODE_ANTIQUE:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x18);  
			ov2643_write(0xb9, 0x40);  
			ov2643_write(0xba, 0xa0);
			break;
		case COLOR_MODE_BLUISH:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x18);  
			ov2643_write(0xb9, 0xa0);  
			ov2643_write(0xba, 0x40);
			break;
		case COLOR_MODE_GREENISH:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x18);  
			ov2643_write(0xb9, 0x60);  
			ov2643_write(0xba, 0x60);
			break;
		case COLOR_MODE_REDDISH:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x18);  
			ov2643_write(0xb9, 0x80);  
			ov2643_write(0xba, 0xc0);
			break;
		case COLOR_MODE_BW:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x20); 
			ov2643_write(0xb9, 0x40);  
			ov2643_write(0xba, 0x40);
			break;
		case COLOR_MODE_NEGATIVE:
			ov2643_write(0xb5, 0x01);
			ov2643_write(0xb6, 0x40); 
			ov2643_write(0xb9, 0x40);  
			ov2643_write(0xba, 0x40);
			break;
		case COLOR_MODE_NORMAL:
		default:
			ov2643_write(0xb5, 0x21);
			ov2643_write(0xb6, 0x00); 
			ov2643_write(0xb9, 0x40);  
			ov2643_write(0xba, 0x28);
		break;
	}

}
void OV2643_reg_write(unsigned char addr,unsigned char val)
{
	ov2643_write(addr,val);

}
unsigned char  OV2643_reg_read(unsigned char addr)
{
	return ov2643_read(addr);
}

uint16_t SPEC_OV2643_reg_read(unsigned char page, unsigned char addr){}
void SPEC_OV2643_reg_write(unsigned char page, unsigned char addr,uint16_t val){}

ColorMaxValue OV2643_get_color_max_value()
{
	ColorMaxValue value_info;
	value_info.HueMax = 255;
	value_info.SaturationMax = 255;
	value_info.ContrastMax= 255;
	value_info.BrightnessMax= 255;

	return value_info;
}

void OV2643_set_shutter(unsigned char val){}



